﻿/* ----------------------------------------------------------------------------
 * Copyright (c) Rob Ashton 2009
 *
 * This source code is subject to terms and conditions of the Microsoft Public 
 * License (Ms-PL).
 * 
 * By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * To request a copy of the Microsoft Public License, send a request by email
 * to license@mvcex.com
 *
 * This notice must not be removed from this software.
 * ---------------------------------------------------------------------------- */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;
using System.Reflection;
using System.Reflection.Emit;

namespace MvcEx.Controllers
{
    public class MvcExControllerFactory : IControllerFactory
    {
        #region Instance Variables

        private IMvcExControllerBuilderSelector mBuilderProvider;
        private Type mBaseType = null;
        private IIocContainer mContainer;

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the IOC container used by this controller factory to inject dependencies into the dynamically 
        /// generated controller constructors
        /// </summary>
        public IIocContainer IocContainer
        {
            get
            {
                return mContainer;
            }
        }

        #endregion

        public void SetIocContainer(IIocContainer container)
        {
            mContainer = container;
        }

        public void SetBaseControllerType(Type type)
        {
            if (!typeof(MvcExController).IsAssignableFrom(type)) 
            { 
                throw new InvalidOperationException("Controller Type must be derived from MvcExController");
            }
            mBaseType = type;
        }

        #region .ctor

        public MvcExControllerFactory(IMvcExControllerBuilderSelector builderProvider)
        {
            mBuilderProvider = builderProvider;
            mContainer = null;
        }

        public MvcExControllerFactory(IMvcExControllerBuilderSelector builderProvider, IIocContainer iocContainer)
        {
            mBuilderProvider = builderProvider;
            mContainer = iocContainer;
        }

        #endregion

        #region IControllerFactory Members

        public IController CreateController(RequestContext requestContext, string controllerName)
        {
            if (controllerName == "favicon.ico") { return null; }

            // Get the builder with which to get our dynamic type
            var builder = mBuilderProvider.GetActiveBuilder();

            // Very well then
            if (builder == null) { return null; }

            // And query that for our controller type
            Type controllerType = builder.GetControllerType(controllerName, mBaseType ?? typeof(MvcExController) );

            // We didn't find it
            if (controllerType == null) { return null; }

            // TODO: Dependency injection based on constructor instead of just giving the controller the IOC Container
            //var constructor = controllerType.GetConstructor(
            //    BindingFlags.Public,
            //    null,
            //    new Type[] { typeof(IIocContainer) },
            //    null);

            //return (IController)constructor.Invoke(new Object[] { this.IocContainer });           
            //// Return an instance of this type
           return (IController)Activator.CreateInstance(controllerType, new Object[] { this.IocContainer });
        }

        public void ReleaseController(IController controller)
        {
            // Nothing to do here, no un-managed resources to speak of
        }

        #endregion
    }
}
